home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / iproute.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  16KB  |  643 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "internet.h"
  7. #include "timer.h"
  8. #include "netuser.h"
  9. #include "ip.h"
  10. #include "icmp.h"
  11. #include "iface.h"
  12. #include "trace.h"
  13. #ifdef    UNIX
  14. #include <memory.h>
  15. #endif
  16. static int16 hash_ip();
  17. static int32 get32();
  18. static struct route *rt_lookup();
  19. struct route *routes[32][NROUTE];    /* Routing table */
  20. struct route r_default;            /* Default route entry */
  21.  
  22. int32 ip_addr;
  23. struct ip_stats ip_stats;
  24.  
  25. #ifndef    GWONLY
  26. struct mbuf *loopq;    /* Queue for loopback packets */
  27. #endif
  28.  
  29. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  30.  * coming or going, must pass.
  31.  *
  32.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  33.  * broadcast. The router will kick the packet upstairs regardless of the
  34.  * IP destination address.
  35.  */
  36. int
  37. ip_route(bp,rxbroadcast)
  38. struct mbuf *bp;
  39. char rxbroadcast;    /* True if packet had link broadcast address */
  40. {
  41.     struct mbuf *htonip();
  42.     void ip_recv();
  43.     struct ip ip;            /* IP header being processed */
  44.     int16 ip_len;            /* IP header length */
  45.     int16 length;            /* Length of data portion */
  46.     int32 gateway;            /* Gateway IP address */
  47.     register struct route *rp;    /* Route table entry */
  48.     struct interface *iface;    /* Output interface, possibly forwarded */
  49.     struct route *rt_lookup();
  50.     int16 offset;            /* Offset into current fragment */
  51.     int16 mf_flag;            /* Original datagram MF flag */
  52.     int strict = 0;            /* Strict source routing flag */
  53.     char precedence;        /* Extracted from tos field */
  54.     char delay;
  55.     char throughput;
  56.     char reliability;
  57.     int16 opt_len;        /* Length of current option */
  58.     char *opt;        /* -> beginning of current option */
  59.     char *ptr;        /* -> pointer field in source route fields */
  60.     struct mbuf *tbp;
  61.  
  62.     ip_stats.total++;
  63.     if(len_mbuf(bp) < IPLEN){
  64.         /* The packet is shorter than a legal IP header */
  65.         ip_stats.runt++;
  66.         free_p(bp);
  67.         return -1;
  68.     }
  69.     /* Sneak a peek at the IP header's IHL field to find its length */
  70.     ip_len = (bp->data[0] & 0xf) << 2;
  71.     if(ip_len < IPLEN){
  72.         /* The IP header length field is too small */
  73.         ip_stats.length++;
  74.         free_p(bp);
  75.         return -1;
  76.     }
  77.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  78.         /* Bad IP header checksum; discard */
  79.         ip_stats.checksum++;
  80.         free_p(bp);
  81.         return -1;
  82.     }
  83.     /* Extract IP header */
  84.     ntohip(&ip,&bp);
  85.  
  86.     if(ip.version != IPVERSION){
  87.         /* We can't handle this version of IP */
  88.         ip_stats.version++;
  89.         free_p(bp);
  90.         return -1;
  91.     }
  92.     /* Trim data segment if necessary. */
  93.     length = ip.length - ip_len;    /* Length of data portion */
  94.     trim_mbuf(&bp,length);    
  95.                 
  96.     /* Process options, if any. Also compute length of secondary IP
  97.      * header in case fragmentation is needed later
  98.      */
  99.     strict = 0;
  100.     for(opt = ip.options; opt < &ip.options[ip.optlen];opt += opt_len){
  101.         int32 get32();
  102.  
  103.         /* Most options have a length field. If this is a EOL or NOOP,
  104.          * this (garbage) value won't be used
  105.          */
  106.         opt_len = uchar(opt[1]);
  107.  
  108.         switch(opt[0] & OPT_NUMBER){
  109.         case IP_EOL:
  110.             goto no_opt;    /* End of options list, we're done */
  111.         case IP_NOOP:
  112.             opt_len = 1;
  113.             break;        /* No operation, skip to next option */
  114.         case IP_SSROUTE:    /* Strict source route & record route */
  115.             strict = 1;    /* note fall-thru */
  116.         case IP_LSROUTE:    /* Loose source route & record route */
  117.             /* Source routes are ignored unless we're in the
  118.              * destination field
  119.              */
  120.             if(ip.dest != ip_addr)
  121.                 break;    /* Skip to next option */
  122.             if(uchar(opt[2]) >= opt_len){
  123.                 break;    /* Route exhausted; it's for us */
  124.             }
  125.             /* Put address for next hop into destination field,
  126.              * put our address into the route field, and bump
  127.              * the pointer
  128.              */
  129.             ptr = opt + uchar(opt[2]) - 1;
  130.             ip.dest = get32(ptr);
  131.             put32(ptr,ip_addr);
  132.             opt[2] += 4;
  133.             break;
  134.         case IP_RROUTE:    /* Record route */
  135.             if(uchar(opt[2]) >= opt_len){
  136.                 /* Route area exhausted; kick back an error */
  137.                 union icmp_args icmp_args;
  138.  
  139.                 icmp_args.pointer = IPLEN + opt - ip.options;
  140.                 icmp_output(&ip,bp,PARAM_PROB,0,&icmp_args);
  141.                 free_p(bp);
  142.                 return -1;
  143.             }
  144.             /* Add our address to the route */
  145.             ptr = opt + uchar(opt[2]) - 1;
  146.             ptr = put32(ptr,ip_addr);
  147.             opt[2] += 4;
  148.             break;
  149.         }
  150.     }
  151. no_opt:
  152.  
  153.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  154.     if(ip.dest == ip_addr || (ip_addr == 0 && ip.source) || rxbroadcast){
  155. #ifdef    GWONLY
  156.     /* We're only a gateway, we have no host level protocols */
  157.         if(!rxbroadcast)
  158.             icmp_output(&ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  159.         free_p(bp);
  160. #else
  161.  
  162.         /* If this is a local loopback packet, place on the loopback
  163.          * queue for processing in the main loop. This prevents the
  164.          * infinite stack recursion and other problems that would
  165.          * otherwise occur when we talk to ourselves, e.g., with ftp
  166.          */
  167.         if(ip.source == ip_addr){
  168.             /* Put IP header back on */
  169.             if((tbp = htonip(&ip,bp,0)) == NULLBUF){
  170.                 free_p(bp);
  171.                 return -1;
  172.             }
  173.             /* Copy loopback packet into new buffer.
  174.              * This avoids an obscure problem with TCP which
  175.              * dups its outgoing data before transmission and
  176.              * then frees it when an ack comes, even though the
  177.              * receiver might not have actually read it yet
  178.              */
  179.             bp = copy_p(tbp,len_mbuf(tbp));
  180.             free_p(tbp);
  181.             if(bp == NULLBUF)
  182.                 return -1;
  183.             enqueue(&loopq,bp);
  184.         } else {
  185.             ip_recv(&ip,bp,rxbroadcast);
  186.         }
  187. #endif
  188.         return 0;
  189.     }
  190.  
  191.     /* Decrement TTL and discard if zero */
  192.     if(--ip.ttl == 0){
  193.         /* Send ICMP "Time Exceeded" message */
  194.         icmp_output(&ip,bp,TIME_EXCEED,0,NULLICMP);
  195.         free_p(bp);
  196.         return -1;
  197.     }
  198.     /* Look up target address in routing table */
  199.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  200.         /* No route exists, return unreachable message */
  201.         icmp_output(&ip,bp,DEST_UNREACH,HOST_UNREACH,NULLICMP);
  202.         free_p(bp);
  203.         return -1;
  204.     }
  205.     /* Check for output forwarding and divert if necessary */
  206.     iface = rp->interface;
  207.     if(iface->forw != NULLIF)
  208.         iface = iface->forw;
  209.  
  210.     /* Find gateway; zero gateway in routing table means "send direct" */
  211.     if(rp->gateway == (int32)0)
  212.         gateway = ip.dest;
  213.     else
  214.         gateway = rp->gateway;
  215.  
  216.     if(strict && gateway != ip.dest){
  217.         /* Strict source routing requires a direct entry */
  218.         icmp_output(&ip,bp,DEST_UNREACH,ROUTE_FAIL,NULLICMP);
  219.         free_p(bp);
  220.         return -1;
  221.     }
  222.     precedence = PREC(ip.tos);
  223.     delay = ip.tos & DELAY;
  224.     throughput = ip.tos & THRUPUT;
  225.     reliability = ip.tos & RELIABILITY;
  226.  
  227.     if(ip.length <= iface->mtu){
  228.         /* Datagram smaller than interface MTU; put header
  229.          * back on and send normally
  230.          */
  231.         if((tbp = htonip(&ip,bp,0)) == NULLBUF){
  232.             free_p(bp);
  233.             return -1;
  234.         }
  235.         return (*iface->send)(tbp,iface,gateway,
  236.             precedence,delay,throughput,reliability);
  237.     }
  238.     /* Fragmentation needed */
  239.     if(ip.fl_offs & DF){
  240.         /* Don't Fragment set; return ICMP message and drop */
  241.         icmp_output(&ip,bp,DEST_UNREACH,FRAG_NEEDED,NULLICMP);
  242.         free_p(bp);
  243.         return -1;
  244.     }
  245.     /* Create fragments */
  246.     offset = (ip.fl_offs & F_OFFSET) << 3;
  247.     mf_flag = ip.fl_offs & MF;    /* Save original MF flag */
  248.     while(length != 0){        /* As long as there's data left */
  249.         int16 fragsize;        /* Size of this fragment's data */
  250.         struct mbuf *f_data;    /* Data portion of fragment */
  251.  
  252.         /* After the first fragment, should remove those
  253.          * options that aren't supposed to be copied on fragmentation
  254.          */
  255.         ip.fl_offs = offset >> 3;
  256.         if(length + ip_len <= iface->mtu){
  257.             /* Last fragment; send all that remains */
  258.             fragsize = length;
  259.             ip.fl_offs |= mf_flag;    /* Pass original MF flag */
  260.         } else {
  261.             /* More to come, so send multiple of 8 bytes */
  262.             fragsize = (iface->mtu - ip_len) & 0xfff8;
  263.             ip.fl_offs |= MF;
  264.         }
  265.         ip.length = fragsize + ip_len;
  266.  
  267.         /* Move the data fragment into a new, separate mbuf */
  268.         if((f_data = alloc_mbuf(fragsize)) == NULLBUF){
  269.             free_p(bp);
  270.             return -1;
  271.         }
  272.         f_data->cnt = pullup(&bp,f_data->data,fragsize);
  273.  
  274.         /* Put IP header back on */
  275.         if((tbp = htonip(&ip,f_data,0)) == NULLBUF){
  276.             free_p(f_data);
  277.             free_p(bp);
  278.             return -1;
  279.         }
  280.         /* and ship it out */
  281.         if((*iface->send)(tbp,iface,gateway,
  282.             precedence,delay,throughput,reliability) == -1)
  283.             return -1;
  284.  
  285.         offset += fragsize;
  286.         length -= fragsize;
  287.     }
  288.     return 0;
  289. }
  290.  
  291. struct rt_cache rt_cache;
  292.  
  293. /* Add an entry to the IP rou